package com.ciaojian.core.util;

import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;

import javax.servlet.http.HttpServletRequest;

/**
 * 幂等性Token
 *
 * @author Atlakyn
 */
public class TokenKit {

    /**
     * api token 请求头名
     */
    private static final String API_TOKEN = "apiToken";

    /**
     * api token redis 前缀
     */
    private static final String API_TOKEN_PREFIX = "API_TOKEN_";

    /**
     * token 存活时间 单位:秒
     */
    private static final int EXPIRE_TIME_SECOND = 60;

    /**
     * 创建token
     *
     * @return 创建的token
     */
    public static String createToken() {
        String str = IdUtil.randomUUID();
        StrBuilder token = new StrBuilder();
        token.append(API_TOKEN_PREFIX).append(str);

        RedisUtil.setKeyTime(token.toString(), EXPIRE_TIME_SECOND, token.toString());

        return token.toString();
    }

    /**
     * 检验token
     *
     * @param request http request请求
     * @return 校验token存在返回true
     */
    public static Boolean checkToken(HttpServletRequest request) {
        String token = request.getHeader(TokenKit.API_TOKEN);
        // header中不存在token
        if (StrUtil.isBlank(token)) {
            token = request.getParameter(TokenKit.API_TOKEN);
            // parameter中也不存在token
            if (StrUtil.isBlank(token)) {
                throw new IllegalArgumentException("请更新小程序版本(删除小程序后重新进入)");
            }
        }

        if (!RedisUtil.exists(token)) {
            throw new IllegalArgumentException(("请勿重复提交"));
        }

        // 不能单纯的直接删除token而不校验是否删除成功, 会出现并发安全性问题
        // 因为,有可能多个线程同时走到这行,此时token还未被删除,所以继续往下执行
        // 如果不校验jedisUtil.remove(token)的删除结果而直接放行,那么还是会出现重复提交问题
        if (!RedisUtil.delKey(token)) {
            throw new IllegalArgumentException(("请勿重复提交"));
        }
        return true;
    }
}